home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / disk / misc / dev_handler1_4.lha / Device-Handler / Device-Handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-23  |  29.6 KB  |  1,032 lines

  1. ;/* "C:Execute" me to compile me with SAS/C 6
  2. Set file Device-Handler
  3.  
  4. sc:c/sc MOD NOICON VERBOSE STRMERGE UNSCHAR NOSTKCHK IGNORE=73 MOD CSRC $file.c
  5. sc:c/slink NOICONS FROM $file.o TO $file LIB lib:amiga.lib,lib:sc.lib,lib:debug.lib VERBOSE SMALLCODE SMALLDATA NODEBUG
  6. protect $file +p
  7.  
  8. UnSet opt
  9. UnSet file
  10. Quit
  11. */
  12.  
  13. /*F*/ /* autodoc */
  14. #if 0
  15. AUTODOC Device-Handler
  16. **
  17. ** $VER: Device-Handler 1.4 (22 Feb 1995)
  18. **
  19. ** Original code was written by Matthias Scheler. The original
  20. ** distribution archive of Matthias has been included.
  21. **
  22. **
  23. ** NAME
  24. **    Device-Handler - UNIX-like raw device access
  25. **
  26. ** WARNING
  27. **    This software is intended for advanced users only. I *strongly*
  28. **    recommend all people who do not understand every detail given
  29. **    herein to obtain further information about ->AmigaDOS-Devices
  30. **    and ->Handlers and their implementation on top of ->Exec
  31. **    device drivers.
  32. **
  33. **    ** WRONG USAGE OF THIS SOFTWARE WILL MOST LIKELY RESULT IN **
  34. **    ** SEVERE LOSS OF DATA!                                    **
  35. **
  36. **    As this software is freeware in cases of data disruption you
  37. **    will find _nobody_ being responsible except yourself. Especially
  38. **    Matthias and me reject any liability.
  39. **
  40. ** FUNCTION
  41. **    Amiga Users often put a jealous glance to the UNIX world, were
  42. **    raw device access is as simple as nowhere else. Several solutions
  43. **    to fix this for Amigas have been provided in the past. One of these,
  44. **    the DEV: handler by Matthias Scheler, has been taken to base this
  45. **    software on.
  46. **
  47. **    Specifically, the original DEV: has the considerable drawback that it
  48. **    only worked with devices that supported the ->TD_GETGEOMETRY
  49. **    ->IORequest. Unfortunatly a lot of harddisk- (and other) drivers don't
  50. **    implement this command.
  51. **
  52. **    So I decided to derive the Exec-device selection from on the AmigaDOS
  53. **    stream name in such way, that the user provides the Name of an
  54. **    AmigaDOS Handler instead of the Exec-Device. There are system conform
  55. **    ways to find out on top of which Exec-device an AmigaDOS handler is
  56. **    running, so why not leaving this job to the DEV:-Handler ?
  57. **
  58. **    With my DEV: enhancement, you may type things like "DEV:df0" or
  59. **    "DEV:dh0", you get the general idea. Further improvements include the
  60. **    ability to limit the total size which is allowed to read or write, and
  61. **    to specify the low- and high cylinders to be used.
  62. **
  63. **    Note that the physical definition is completely retrieved from the
  64. **    given handler name (e.g. dh0), so there are some implications:
  65. **
  66. **       * Exec-device will be always correct
  67. **       * Exec-device unit will be allways correspond to the unit
  68. **         the AmigaDOS handler works on, releasing you from dealing whith
  69. **         it and thus making the usage of DEV: _much_ safer!
  70. **       * Exec-device OpenDevice() flags are always correct
  71. **       * Exec-device buffer memory type is always correct
  72. **       * Most often you will want to use DEV: for ->UNIX tar and will want
  73. **         to start writing exactly at block 0. For most floppy-base devices
  74. **         this will be correct automatically. In contrast, nearly every
  75. **         harddisk contains a ->RigidDiskBlock and the actual partitions
  76. **         are located behind this, usually having a low-cylinder of about 3.
  77. **         To archieve the intended bahaviour, you should create a special
  78. **         DOSDriver/mountlist entry, such as:
  79. **
  80. **           RDH0:                       /* raw dh0 */
  81. **              Device = scsi.device     /* change this accordingly */
  82. **              Unit = 1
  83. **              Flags = 0
  84. **              Surfaces = 5
  85. **              BlocksPerTrack = 17
  86. **              LowCyl = 0 ;             /* specify here full range */
  87. **              HighCyl = 1023           /* of cylinders */
  88. **              Stacksize = 4000
  89. **              Priority = 5
  90. **              GlobVec = -1
  91. **              BufMemType = 0
  92. **           #
  93. **
  94. **         Another way is to use the LOCYL stream name option. Again note:
  95. **         Playing around with LOCYL or HICYL is a pretty dangerous thing.
  96. **         It is always advised to write a dedicated mountlist/DOSDriver.
  97. **
  98. **    Plead read also the original documentation of the DEV:-handler.
  99. **
  100. ** STREAM NAME
  101. **
  102. **    The stream name is constructed as following:
  103. **
  104. **       DEV:<DOSHANDLER>[/<MAXLEN>][/LOCYL=<NUM>][/HICYL=<NUM>]
  105. **
  106. **    During stream name processing, all slashes are removed, thus creating
  107. **    a standard AmigaDOS ReadArgs()-style text line, as you know it from
  108. **    all CLI-Programs (I suppose you deleted all those that don't use
  109. **    ReadArgs() ;).
  110. **
  111. **    Additionally, all dots ('.') which are not part of a quoted text, are
  112. **    substituted by an equation symbol ('='). That comes in handy when using
  113. **    the LOCYL or HICYL options. AmigaDOS strips all equations that are not
  114. **    quoted. Thus, the command "type dev:df0/locyl=3" would lead to an error,
  115. **    as the handler would get the text "dev:df0/locyl" instead of
  116. **    "dev:df0/locyl=3". So, either use the dot or quote the whole stream spec.
  117. **
  118. **    *Any* number which is to pass to the handler may start with '$' or '0x'
  119. **    or '0X' to indicate hexadecimal notation (default is decimal). A
  120. **    trailing 'M' tells the handler to interprete it as a mega-value,
  121. **    (i.e. multiply by 1024^2) and 'K' to signal a kilo value (factor 1024).
  122. **    All charactes are case-insensitive.
  123. **
  124. **    The complete convenience of ReadArgs() applies to stream name
  125. **    construction:
  126. **
  127. **       The template is "DOSHANDLER/A,MAXLEN,LOCYL/K,HICYL/K"
  128. **
  129. **       DOSNAME
  130. **          A valid, AmigaDOS-device name such as DH0, df0, ... The device has
  131. **          to be mounted, though.
  132. **
  133. **       MAXLEN
  134. **          optional: maximum length of bytes to read or write. The (final)
  135. **          lo/hicyl may enclose a smaller space: the smallest space is always
  136. **          used. This value _must_ appear anywhere behind DOSHANDLER.
  137. **
  138. **       LOCYL
  139. **          Starting cylinder read from/write to. If higher than the (final)
  140. **          high cylinder, low cylinder is casted to high cylinder.
  141. **
  142. **       HICYL
  143. **          Ending cylinder. If higher than physical, physical is used.
  144. **
  145. **    Some example stream names:
  146. **
  147. **       DEV:df0
  148. **       DEV:dh0/1024
  149. **       DEV:dh0/1k
  150. **       DEV:dh0/LOCYL=0
  151. **       DEV:dh1/HICYL=1k/LOCYL=0M/20M
  152. **       DEV:df0/$1000
  153. **       DEV:df0/0x2000/LOCYL.4
  154. **       "DEV:df0/0X200/LOCYL=4"
  155. **
  156. ** AUTHOR
  157. **
  158. **    Marius Gröger,
  159. **    Bärstadter Str. 4
  160. **    D-65307 Bad Schwalbach
  161. **    email: mag@sysgo.de
  162. **
  163. ** SOURCE
  164. **
  165. **    The source code of "Device-Handler" has been written with the GoldED
  166. **    text editor (© Dietmar Eilert). Text folds start with "/*F*/"
  167. **    and end with "/*E*/".
  168. **
  169. **    You may make any changes to the source for your own use.
  170. **    If you consider them useful for everybody, tell me so I can
  171. **    include them to the next public release.
  172. **
  173. **    The documentation has been extracted with makedoc (© Stefan Ruppert).
  174. **
  175. ** $HISTORY:
  176. **
  177. ** 22 Feb 1995 : 001.004 :  some bug-fixing
  178. ** 18 Feb 1995 : 001.003 :  made Write() working...
  179. ** 20 Dec 1994 : 001.002 :  + one task/multiple FileHandles
  180. **                          + source-code rework
  181. **                          + better stream name scanning by ReadArgs()
  182. **                          + new option MAXLENGTH
  183. **                          + new options LOCYL, HICYL
  184. **                          + highly improved read/write operation
  185. ** 18 Dec 1994 : 001.001 :  changed stream name convention
  186. ** 08 Dec 1994 : 001.000 :  took over from Matthias Scheler
  187. **
  188. ENDDOC
  189. **
  190. #endif
  191. /*E*/
  192.  
  193. /*F*/ /* debug */
  194. extern void KPrintF(char *, ...);
  195. /*#define d(x) { KPrintF("%s:%ld: ", __FUNC__, __LINE__); KPrintF x; }*/
  196. #define d(x) ;
  197. /*E*/
  198.  
  199. /*F*/ /* includes */
  200. #include <exec/memory.h>
  201. #include <exec/execbase.h>
  202. #include <devices/trackdisk.h>
  203. #include <dos/dosextens.h>
  204. #include <dos/filehandler.h>
  205. #include <dos/dos.h>
  206.  
  207. #define __USE_SYSBASE
  208.  
  209. #include <clib/exec_protos.h>
  210. #include <pragmas/exec_pragmas.h>
  211.  
  212. #include <clib/dos_protos.h>
  213. #include <pragmas/dos_pragmas.h>
  214.  
  215. #include <clib/utility_protos.h>
  216. #include <pragmas/utility_pragmas.h>
  217.  
  218. #include <string.h>
  219.  
  220. /* fix include files (anyawy I'm not yet using them:
  221. ** what about sending me a diff-file ?)
  222. */
  223.  
  224. #ifndef ACTION_GET_DISK_FSSM
  225. #define ACTION_GET_DISK_FSSM 4201
  226. #endif
  227.  
  228. #ifndef ACTION_FREE_DISK_FSSM
  229. #define ACTION_FREE_DISK_FSSM 4202
  230. #endif
  231.  
  232. /*E*/
  233.  
  234. /*F*/ /* declarations */
  235.  
  236. typedef struct GlobalData {
  237.    struct Library *gd_SysBase, *gd_DOSBase, *gd_UtilityBase;
  238.    struct MsgPort *gd_Port;
  239.    struct DosList *gd_DosList;
  240.    struct Process *gd_We;
  241. } *GD;
  242.  
  243. #define SysBase (gd->gd_SysBase)
  244. #define DOSBase (gd->gd_DOSBase)
  245. #define UtilityBase (gd->gd_UtilityBase)
  246.  
  247. #define BCPL_MAXNAME 256
  248. struct PrivateStreamData
  249. {
  250.    struct IOStdReq *psd_IO;
  251.    UBYTE  psd_DOSName[BCPL_MAXNAME];
  252.    UBYTE  psd_Device[32];
  253.    ULONG  psd_Unit;
  254.    ULONG  psd_Flags;
  255.    ULONG  psd_BufMemType;
  256.    LONG  psd_LoCyl, psd_HiCyl;
  257.    LONG  psd_SectorSize;
  258.    LONG  psd_Offset;
  259.    LONG  psd_MaxLength;
  260.  
  261.    LONG  psd_Pos;
  262.    LONG  psd_Len;
  263.    LONG  psd_Left;
  264.    UBYTE *psd_Buffer;
  265.    UBYTE *psd_Ptr;
  266.    BOOL   psd_Write;
  267. };
  268.  
  269. #define MIN __builtin_min
  270. #define MAX __builtin_min
  271.  
  272. #define STREAMNAME_TEMPLATE "DOSNAME/A,MAXLENGTH,LOCYL/K,HICYL/K"
  273. enum { ARG_DOSNAME=0, ARG_MAXLENGTH, ARG_LOCYL, ARG_HICYL, ARG_COUNT };
  274.  
  275. /*E*/
  276.  
  277. /*F*/ /* entry */
  278. static ULONG main(void);
  279. static ULONG __saveds __asm entry(register __a0 UBYTE *line, register __d0 ULONG len)
  280. {
  281.    return(main());
  282. }
  283.  
  284. const static UBYTE version[]= "\0$VER: Device-Handler 1.4 "__AMIGADATE__;
  285.  
  286. /*E*/
  287.  
  288. /*F*/ static struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port)
  289.  
  290. {
  291.    WaitPort(port);
  292.    return (struct DosPacket *)(GetMsg(port)->mn_Node.ln_Name);
  293. }
  294. /*E*/
  295. /*F*/ static void ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2)
  296. {
  297.    struct MsgPort *reply = Packet->dp_Port;
  298.  
  299.    Packet->dp_Port = port;
  300.    Packet->dp_Link->mn_Node.ln_Name = (char *)Packet;
  301.    Packet->dp_Res1 = Res1;
  302.    Packet->dp_Res2 = Res2;
  303.  
  304.    PutMsg (reply, Packet->dp_Link);
  305. }
  306. /*E*/
  307.  
  308. /*F*/ static BOOL openres(GD gd)
  309. {
  310.    BOOL rc = FALSE;
  311.  
  312.    d(("entered\n"))
  313.  
  314.    DOSBase = NULL;
  315.    UtilityBase = NULL;
  316.    gd->gd_Port = NULL;
  317.  
  318.    if (SysBase->lib_Version >= 37)
  319.    {
  320.       if (DOSBase = OpenLibrary("dos.library", 37))
  321.       {
  322.          if (UtilityBase = OpenLibrary("utility.library", 37))
  323.          {
  324.             if (gd->gd_Port = CreateMsgPort())
  325.             {
  326.                rc = TRUE;
  327.             }
  328.             else d(("no handler port\n"))
  329.          }
  330.          else d(("no utility V37\n"))
  331.       }
  332.       else d(("no dos V37\n"))
  333.    }
  334.    else d(("no exec V37\n"))
  335.  
  336.    d(("left: %ld\n",rc))
  337.  
  338.    return rc;
  339. }
  340. /*E*/
  341. /*F*/ static void closeres(GD gd)
  342. {
  343.    d(("freeing port\n"))
  344.    if (gd->gd_Port) DeleteMsgPort(gd->gd_Port);
  345.  
  346.    d(("closing dos\n"))
  347.    if (DOSBase) CloseLibrary(DOSBase);
  348.  
  349.    d(("closing utility\n"))
  350.    if (UtilityBase) CloseLibrary(UtilityBase);
  351. }
  352. /*E*/
  353.  
  354. /*F*/ BOOL getul(GD gd, UBYTE *s, LONG *number)
  355. {
  356.  
  357. #define IsDigit(c) ((c) >= '0' && (c) <= '9'))
  358. #define IsXDigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
  359.  
  360.    BOOL hex, rc = TRUE;
  361.    ULONG num;
  362.    UBYTE c;
  363.    WORD len;
  364.  
  365.    if (len = strlen(s))
  366.    {
  367.       if (!Strnicmp(s, "0x", 2))
  368.       {
  369.          hex = TRUE;
  370.          s += 2;
  371.       }
  372.       else if (!Strnicmp(s, "$", 2))
  373.       {
  374.          hex = TRUE;
  375.          s++;
  376.       }
  377.       else hex = FALSE;
  378.  
  379.       for(num=0;*s;s++)
  380.       {
  381.          c = ToUpper(*s);
  382.          if (hex)
  383.          {
  384.             if (c >= '0' && c <= '9') num = num * 16 + c - '0';
  385.             else if (c >= 'A' && c <= 'F') num = num * 16 + c - '0';
  386.             else break;
  387.          }
  388.          else
  389.          {
  390.             if (c >= '0' && c <= '9') num = num * 10 + c - '0';
  391.             else break;
  392.          }
  393.       }
  394.  
  395.       if (*s)
  396.       {
  397.          if (c == 'K') num *= 1024;
  398.          else if (c == 'M') num *= 1024*1024;
  399.          else rc = FALSE;
  400.       }
  401.    }
  402.    else rc = FALSE;
  403.  
  404.    if (rc) *number = num;
  405.  
  406.    return rc;
  407. }
  408. /*E*/
  409. /*F*/ static void stream2rdargs(UBYTE *buffer)
  410. {
  411.    UBYTE *p;
  412.    enum { s_norm, s_esc, s_quote } s;
  413.  
  414.    for (p = buffer, s = s_norm; *p; p++)
  415.       switch(s)
  416.       {
  417.          case s_norm:
  418.             if (*p == '.') *p = '=';
  419.             if (*p == '/') *p = '\040';
  420.             else if (*p == '"') s = s_quote;
  421.          break;
  422.          case s_esc:
  423.             s = s_quote;
  424.          break;
  425.          case s_quote:
  426.             if (*p == '*') s = s_esc;
  427.             if (*p == '"') s = s_norm;
  428.          break;
  429.       }
  430. }
  431. /*E*/
  432. /*F*/ static BOOL streamspecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res)
  433. {
  434.    UBYTE *temp, *bstr, *start;
  435.    BOOL rc = FALSE;
  436.    LONG rdparam[ARG_COUNT];
  437.    struct RDArgs *inrda, *rda;
  438.  
  439.    bstr = (UBYTE *)BADDR(streamname);
  440.  
  441.    if (temp = AllocVec(bstr[0]+2, MEMF_ANY))
  442.    {
  443.       if (inrda = AllocDosObject(DOS_RDARGS, NULL))
  444.       {
  445.          strncpy(temp, bstr+1, bstr[0]);
  446.          temp[bstr[0]] = '\n';
  447.          temp[bstr[0]+1] = '\0';
  448.  
  449.          if (start = (UBYTE*)strchr((char*)temp, ':'))
  450.          {
  451.             stream2rdargs(++start);
  452.  
  453.             inrda->RDA_Source.CS_Buffer = start;
  454.             inrda->RDA_Source.CS_Length = strlen(start);
  455.             inrda->RDA_Source.CS_CurChr = 0;
  456.  
  457.             psd->psd_MaxLength = 0x7fffffff;
  458.             psd->psd_LoCyl = 0;
  459.             psd->psd_HiCyl = 0x7fffffff;
  460.             memset(rdparam, 0, ARG_COUNT*sizeof(LONG));
  461.             d(("readargs(%s)\n",start))
  462.             if (rda = ReadArgs((UBYTE*)STREAMNAME_TEMPLATE, rdparam, inrda))
  463.             {
  464.                rc = TRUE;
  465.  
  466.                strcpy(psd->psd_DOSName, (UBYTE*)rdparam[ARG_DOSNAME]);
  467.                if (rdparam[ARG_MAXLENGTH]) rc = getul(gd,(UBYTE*)rdparam[ARG_MAXLENGTH], &psd->psd_MaxLength);
  468.                if (rc && rdparam[ARG_LOCYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_LOCYL], &psd->psd_LoCyl);
  469.                if (rc && rdparam[ARG_HICYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_HICYL], &psd->psd_HiCyl);
  470.  
  471.                d(("after ReadArgs(): doshandler %s maxlen %lu locyl %lu hicyl %lu\n",
  472.                   psd->psd_DOSName,psd->psd_MaxLength,psd->psd_LoCyl,psd->psd_HiCyl))
  473.  
  474.                FreeArgs(rda);
  475.             }
  476.             else
  477.             {
  478.                d(("ReadArgs() failed\n"))
  479.                *res = ERROR_BAD_STREAM_NAME;
  480.             }
  481.          }
  482.          else
  483.          {
  484.             d(("no proper name\n"))
  485.             *res = ERROR_BAD_STREAM_NAME;
  486.          }
  487.  
  488.          FreeDosObject(DOS_RDARGS, inrda);
  489.       }
  490.       else
  491.       {
  492.          d(("no RDArgs\n"))
  493.          *res = ERROR_NO_FREE_STORE;
  494.       }
  495.  
  496.       FreeVec(temp);
  497.    }
  498.    else
  499.    {
  500.       d(("no more memory\n"))
  501.       *res = ERROR_NO_FREE_STORE;
  502.    }
  503.  
  504.    return rc;
  505. }
  506. /*E*/
  507.  
  508. /*F*/ static BOOL FindDevice(GD gd, struct PrivateStreamData *psd)
  509. {
  510.    struct DosList *dol;
  511.    struct FileSysStartupMsg *fssm=NULL;
  512.    BOOL rc = FALSE;
  513.    UBYTE *name;
  514.    UBYTE n;
  515.    UBYTE pat[40];
  516.  
  517.    d(("entered: %s\n", psd->psd_DOSName))
  518.  
  519.    n = strlen(psd->psd_DOSName);
  520.  
  521.    if (dol = LockDosList(LDF_READ | LDF_DEVICES))
  522.    {
  523.       while(dol = NextDosEntry(dol, LDF_DEVICES))
  524.       {
  525.          name = (UBYTE*)BADDR(dol->dol_Name);
  526.  
  527.          memset(pat,0,40);
  528.          strncpy(pat,name+1,name[0]);
  529.          d(("%s\n",pat))
  530.  
  531.          if ((n == name[0]) && !Strnicmp((char*)(name+1), psd->psd_DOSName, n))
  532.          {
  533.             d(("found\n"))
  534.  
  535.             fssm = (struct FileSysStartupMsg*)BADDR(dol->dol_misc.dol_handler.dol_Startup);
  536.  
  537.             if (fssm)
  538.             {
  539.                struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
  540.  
  541.                d(("found fssm\n"))
  542.                   /* note: fssm->fssm_Device is a NUL terminated BSTR!! :-) */
  543.                strcpy((char*)psd->psd_Device, (char*)BADDR(fssm->fssm_Device)+1);
  544.                psd->psd_Flags = fssm->fssm_Flags;
  545.                psd->psd_Unit = fssm->fssm_Unit;
  546.                psd->psd_BufMemType = de->de_BufMemType;
  547.                psd->psd_SectorSize = 4 * de->de_SizeBlock;
  548.                psd->psd_HiCyl = MIN(psd->psd_HiCyl, de->de_HighCyl);
  549.                psd->psd_LoCyl = MIN(psd->psd_LoCyl, psd->psd_HiCyl);
  550.                d(("de->de_BlocksPerTrack %ld, psd->psd_LoCyl %ld, de->de_Surfaces %ld, psd->psd_SectorSize %ld\n",
  551.                   de->de_BlocksPerTrack,psd->psd_LoCyl,de->de_Surfaces,psd->psd_SectorSize))
  552.                psd->psd_Offset = de->de_BlocksPerTrack * psd->psd_LoCyl * de->de_Surfaces * psd->psd_SectorSize;
  553.  
  554.                psd->psd_Len = de->de_BlocksPerTrack * psd->psd_SectorSize * (psd->psd_HiCyl - psd->psd_LoCyl + 1) * de->de_Surfaces;
  555.                psd->psd_Len = MIN(psd->psd_MaxLength, psd->psd_Len);
  556.                d(("len %lu\n",psd->psd_Len))
  557.  
  558.                d(("device %s, unit %ld, flags %ld, secsiz %ld, off %ld\n",
  559.                   psd->psd_Device,psd->psd_Unit,psd->psd_Flags,psd->psd_SectorSize,psd->psd_Offset))
  560.  
  561.                rc = TRUE;
  562.             }
  563.             else
  564.                d(("no fssm\n"))
  565.  
  566.             break;
  567.          }
  568.       }
  569.  
  570.       UnLockDosList(LDF_READ | LDF_DEVICES);
  571.    }
  572.  
  573.    return(rc);
  574. }
  575. /*E*/
  576.  
  577. /*F*/ static void __regargs OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt)
  578. {
  579.    struct FileHandle *FH;
  580.    struct PrivateStreamData *psd;
  581.    struct MsgPort *IOPort;
  582.    BOOL ok = FALSE;
  583.  
  584.    Pkt->dp_Res1 = DOSFALSE;
  585.    FH = (struct FileHandle *)BADDR(Pkt->dp_Arg1);
  586.    FH->fh_Port = (struct MsgPort *)FALSE;
  587.    FH->fh_Arg1 = 0L;
  588.  
  589.    d(("allocing psd\n"))
  590.    if (psd = AllocVec(sizeof(*psd),MEMF_PUBLIC|MEMF_CLEAR))
  591.    {
  592.       if (streamspecs(gd, psd, (BPTR)Pkt->dp_Arg3, &Pkt->dp_Res2))
  593.       {
  594.          d(("creating msgport\n"))
  595.          if (IOPort=CreateMsgPort())
  596.          {
  597.             if (psd->psd_IO=CreateIORequest(IOPort, sizeof(struct IOStdReq)))
  598.             {
  599.                if (FindDevice(gd, psd))
  600.                {
  601.                   if (OpenDevice(psd->psd_Device, psd->psd_Unit, (struct IORequest *)psd->psd_IO, psd->psd_Flags)==0L)
  602.                   {
  603.                      if (psd->psd_Buffer = AllocVec(psd->psd_SectorSize, psd->psd_BufMemType))
  604.                      {
  605.                         if (Pkt->dp_Type == ACTION_FINDOUTPUT)
  606.                         {
  607.                            psd->psd_Write = TRUE;
  608.                            psd->psd_IO->io_Command = CMD_WRITE;
  609.                         }
  610.                         else
  611.                         {
  612.                            psd->psd_Write = FALSE;
  613.                            psd->psd_IO->io_Command = CMD_READ;
  614.                         }
  615.                         psd->psd_Ptr = psd->psd_Buffer;
  616.                         psd->psd_Pos = 0;
  617.                         psd->psd_Left = 0;
  618.  
  619.                         FH->fh_Arg1 = (LONG)psd;
  620.  
  621.                         Pkt->dp_Res1 = DOSTRUE;
  622.                         Pkt->dp_Res2 = 0L;
  623.  
  624.                         (*OpenCnt)++;
  625.                         ok = TRUE;
  626.                      }
  627.                      else Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  628.  
  629.                      if (!ok) CloseDevice ((struct IORequest *)psd->psd_IO);
  630.                   }
  631.                   else
  632.                   {
  633.                      d(("could not open device >%s<\n",psd->psd_Device))
  634.                      Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  635.                   }
  636.                }
  637.                else
  638.                {
  639.                   d(("no device\n"))
  640.                   Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  641.                }
  642.  
  643.                if (!ok) DeleteIORequest(psd->psd_IO);
  644.             }
  645.             else
  646.             {
  647.                d(("no iorequest\n"))
  648.                Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  649.             }
  650.  
  651.             if (!ok) DeleteMsgPort (IOPort);
  652.          }
  653.          else
  654.          {
  655.             d(("no msgport\n"))
  656.             Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  657.          }
  658.       }
  659.       else
  660.       {
  661.          d(("no streamspecs()\n"))
  662.       }
  663.       if (!ok) FreeVec (psd);
  664.    }
  665.    else
  666.    {
  667.        d(("no psd\n"))
  668.        Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
  669.    }
  670.  
  671.    d(("leaving OpenDH() with Res2 = %ld\n",Pkt->dp_Res2))
  672. }
  673. /*E*/
  674. /*F*/ static void __regargs CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt)
  675. {
  676.    d(("CloseDH()\n"))
  677.    if (psd->psd_Write)
  678.    {
  679.       if (psd->psd_Left < psd->psd_SectorSize)
  680.       {
  681.          d(("DoIO(CMD_WRITE)\n"))
  682.  
  683.          memset(psd->psd_Ptr,'\0',psd->psd_Left);
  684.          psd->psd_IO->io_Length  = psd->psd_SectorSize;
  685.          psd->psd_IO->io_Data    = psd->psd_Buffer;
  686.          psd->psd_IO->io_Offset  = psd->psd_Pos + psd->psd_Left-psd->psd_SectorSize;
  687.          DoIO((struct IORequest *)psd->psd_IO);
  688.       }
  689.       psd->psd_IO->io_Command=CMD_UPDATE;
  690.  
  691.       d(("DoIO(CMD_UPDATE)\n"))
  692.       DoIO((struct IORequest *)psd->psd_IO);
  693.    }
  694.  
  695.    d(("FreeVec() buffer\n"))
  696.  
  697.    FreeVec(psd->psd_Buffer);
  698.  
  699.    d(("stopping motor off\n"))
  700.    psd->psd_IO->io_Command = TD_MOTOR;
  701.    psd->psd_IO->io_Length = 0L;
  702.    DoIO((struct IORequest *)psd->psd_IO);
  703.    d(("closing device\n"))
  704.    CloseDevice ((struct IORequest *)psd->psd_IO);
  705.  
  706.    d(("deleting msg port\n"))
  707.    DeleteMsgPort (psd->psd_IO->io_Message.mn_ReplyPort);
  708.  
  709.    d(("deleting stdio\n"))
  710.    DeleteIORequest (psd->psd_IO);
  711.  
  712.    d(("FreeVec() rh\n"))
  713.    FreeVec (psd);
  714.  
  715.    (*OpenCnt)--;
  716.  
  717.    d(("leaving closedh()\n"))
  718.  
  719. }
  720. /*E*/
  721.  
  722. /*F*/ static LONG __regargs RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2)
  723. {
  724.    LONG LatchBytes, RDBytes;
  725.    BOOL error = FALSE;
  726.  
  727.    LatchBytes = Bytes;
  728.  
  729.       /* check bouunds */
  730.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len - psd->psd_Pos;
  731.  
  732.    d(("read %ld bytes\n",Bytes))
  733.  
  734.    /*
  735.    ** first, read what's left in buffer
  736.    */
  737.    if (psd->psd_Left)
  738.    {
  739.       RDBytes=MIN(psd->psd_Left, Bytes);
  740.       CopyMem(psd->psd_Ptr, Buffer, RDBytes);
  741.  
  742.       Buffer += RDBytes;
  743.       Bytes -= RDBytes;
  744.  
  745.       psd->psd_Pos += RDBytes;   /* incr. position in file */
  746.       psd->psd_Ptr += RDBytes;
  747.       psd->psd_Left -= RDBytes;
  748.    }
  749.  
  750.    /*
  751.    ** second, try to read as much blocks as possible directly to
  752.    ** user buffer, avoiding CopyMem()
  753.    */
  754.    if (!error && (Bytes > psd->psd_SectorSize))
  755.    {
  756.       RDBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  757.  
  758.       psd->psd_IO->io_Data = Buffer;
  759.       psd->psd_IO->io_Length = RDBytes;
  760.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  761.       if (DoIO((struct IORequest *)psd->psd_IO))
  762.       {
  763.          RDBytes = psd->psd_IO->io_Actual;
  764.          error = TRUE;
  765.          *res2 = psd->psd_IO->io_Error;
  766.       }
  767.       Buffer += RDBytes;
  768.       Bytes -= RDBytes;
  769.  
  770.       psd->psd_Pos += RDBytes;         /* incr. position in file */
  771.       psd->psd_Left = 0;               /* for safety, initialise buffer */
  772.       psd->psd_Ptr = psd->psd_Buffer;
  773.    }
  774.  
  775.    if (!error && Bytes)
  776.    {
  777.       /*
  778.       ** now there are only some bytes < SectorSize left, so they fit into one buffer
  779.       ** So, read a buffer and copy some bytes from it to user-buffer.
  780.       */
  781.       RDBytes = Bytes;
  782.       psd->psd_IO->io_Length = psd->psd_SectorSize;
  783.       psd->psd_IO->io_Data = psd->psd_Buffer;
  784.       psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  785.  
  786.       if (DoIO((struct IORequest *)psd->psd_IO))
  787.       {
  788.          *res2 = psd->psd_IO->io_Error;
  789.          RDBytes = psd->psd_IO->io_Actual;
  790.       }
  791.  
  792.       CopyMem(psd->psd_Buffer, Buffer, RDBytes);
  793.  
  794.       psd->psd_Pos += RDBytes;
  795.       psd->psd_Ptr = psd->psd_Buffer + RDBytes;
  796.       psd->psd_Left = psd->psd_SectorSize - RDBytes;
  797.  
  798.       Bytes -= RDBytes;
  799.    }
  800.  
  801.    return LatchBytes - Bytes;
  802. }
  803. /*E*/
  804. /*F*/ static LONG __regargs RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2)
  805. {
  806.    LONG LatchBytes,WRBytes;
  807.    BOOL error = FALSE;
  808.  
  809.    LatchBytes = Bytes;
  810.  
  811.       /* check bouunds */
  812.    if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len-psd->psd_Pos;
  813.  
  814.    d(("write %ld bytes\n",Bytes))
  815.  
  816.    /*
  817.    ** first, take care for outstanding data
  818.    */
  819.    if (Bytes && psd->psd_Left)
  820.    {
  821.       WRBytes = MIN(psd->psd_Left, Bytes);
  822.       CopyMem(Buffer, psd->psd_Ptr, WRBytes);
  823.  
  824.       psd->psd_Ptr += WRBytes;      /* incr. position in buffer */
  825.       psd->psd_Left -= WRBytes;     /* decr. number of unused bytes */
  826.  
  827.       if (psd->psd_Left == 0)       /* Buffer full ? */
  828.       {                             /* then write it out */
  829.          psd->psd_IO->io_Data = psd->psd_Buffer;
  830.          psd->psd_IO->io_Length = psd->psd_SectorSize;
  831.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  832.          psd->psd_IO->io_Command = CMD_WRITE;
  833.          if (DoIO((struct IORequest *)psd->psd_IO))
  834.          {
  835.             *res2 = psd->psd_IO->io_Error;
  836.             WRBytes = psd->psd_IO->io_Actual;
  837.             error = TRUE;
  838.          }
  839.  
  840.          psd->psd_Ptr = psd->psd_Buffer;  /* reset buffer pointers */
  841.          psd->psd_Left = 0;
  842.       }
  843.  
  844.       Buffer += WRBytes;
  845.       Bytes -= WRBytes;
  846.       psd->psd_Pos += WRBytes;      /* incr. position in file */
  847.    }
  848.  
  849.    if (!error && Bytes)
  850.    {
  851.       /*
  852.       ** second, try to write as much blocks as possible directly from
  853.       ** user buffer in one go, avoiding CopyMem() and multiple I/O-Requests
  854.       */
  855.       if (Bytes > psd->psd_SectorSize)
  856.       {
  857.             /* I don't like to use bit masking at this point */
  858.          WRBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
  859.  
  860.          psd->psd_IO->io_Data = Buffer;
  861.          psd->psd_IO->io_Length = WRBytes;
  862.          psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
  863.          psd->psd_IO->io_Command = CMD_WRITE;
  864.          if (DoIO((struct IORequest *)psd->psd_IO))
  865.          {
  866.             *res2 = psd->psd_IO->io_Error;
  867.             WRBytes = psd->psd_IO->io_Actual;
  868.             error = TRUE;
  869.          }
  870.  
  871.          Buffer += WRBytes;
  872.          Bytes -= WRBytes;
  873.          psd->psd_Pos += WRBytes;   /* incr. position in file */
  874.  
  875.          psd->psd_Ptr = psd->psd_Buffer;  /* for safety, reset buffer pointers */
  876.          psd->psd_Left = 0;
  877.       }
  878.    }
  879.  
  880.    if (!error && Bytes)
  881.    {
  882.       /*
  883.       ** now there are only some bytes < SectorSize left, and they fit into one
  884.       ** buffer.
  885.       ** NOTE: the actual writing is delayed to Close() or further Write()'s
  886.       */
  887.       WRBytes = Bytes;
  888.       CopyMem(Buffer, psd->psd_Buffer, WRBytes);
  889.  
  890.       psd->psd_Pos += WRBytes;     /* incr. position in file */
  891.       Bytes -= WRBytes;
  892.       Buffer += WRBytes;
  893.  
  894.       psd->psd_Ptr = psd->psd_Buffer + WRBytes;     /* set position in buffer */
  895.       psd->psd_Left = psd->psd_SectorSize - WRBytes; /* set number of unused bytes */
  896.    }
  897.  
  898.    return LatchBytes - Bytes;
  899. }
  900. /*E*/
  901.  
  902. /*F*/ static ULONG main(void)
  903. {
  904.    struct GlobalData GlobalData;
  905.    struct GlobalData *gd;
  906.  
  907.    struct DosPacket *Pkt;
  908.    BOOL Done;
  909.    ULONG OpenCnt;
  910.  
  911.    gd = &GlobalData;
  912.  
  913.    d(("Hello, this is the DEV-Handler\n"))
  914.  
  915.    SysBase = *(struct Library**)4L;
  916.  
  917.    if ((gd->gd_We = (struct Process *)FindTask(NULL))->pr_CLI) return RETURN_FAIL;
  918.  
  919.    d(("waiting for startup-packet...\n"))
  920.    Pkt = WaitDosPacket(gd, &gd->gd_We->pr_MsgPort);
  921.  
  922.    if (openres(gd))
  923.    {
  924.       gd->gd_DosList = (struct DosList *)BADDR(Pkt->dp_Arg3);
  925.       gd->gd_DosList->dol_Task = gd->gd_Port;
  926.  
  927.       d(("replying startup-packet...\n"))
  928.       ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSTRUE, Pkt->dp_Res2);
  929.  
  930.       Done=FALSE;
  931.       OpenCnt=0L;
  932.  
  933.       d(("entering mainloop\n"))
  934.  
  935.       while (!Done)
  936.       {
  937.          Pkt=WaitDosPacket(gd, gd->gd_Port);
  938.  
  939.          d(("got packet %ld\n",Pkt->dp_Type))
  940.  
  941.          Pkt->dp_Res1 = DOSFALSE;
  942.          Pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  943.  
  944.          switch (Pkt->dp_Type)
  945.          {
  946.             case ACTION_FINDINPUT:
  947.             case ACTION_FINDOUTPUT:
  948.                OpenDH (gd, Pkt, &OpenCnt);
  949.                ReplyDosPacket(gd, gd->gd_Port,Pkt, Pkt->dp_Res1, Pkt->dp_Res2);
  950.             break;
  951.  
  952.             case ACTION_END:
  953.                CloseDH (gd, (struct PrivateStreamData *)Pkt->dp_Arg1,&OpenCnt);
  954.                ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  955.             break;
  956.  
  957.             case ACTION_READ:
  958.             {
  959.                struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  960.  
  961.                if (psd && !psd->psd_Write)
  962.                {
  963.                   LONG Bytes, error;
  964.  
  965.                   Bytes = RawRead(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  966.                                       (UBYTE *)Pkt->dp_Arg2,Pkt->dp_Arg3, &error);
  967.  
  968.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  969.                }
  970.             }
  971.             break;
  972.  
  973.             case ACTION_WRITE:
  974.             {
  975.                struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
  976.  
  977.                if (psd && psd->psd_Write)
  978.                {
  979.                   LONG Bytes, error;
  980.  
  981.                   Bytes = RawWrite(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
  982.                                        (UBYTE *)Pkt->dp_Arg2, Pkt->dp_Arg3, &error);
  983.  
  984.                   ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
  985.                }
  986.             }
  987.             break;
  988.  
  989.             case ACTION_IS_FILESYSTEM:
  990.                ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE, 0);
  991.             break;
  992.  
  993.             case ACTION_SEEK:
  994.             case ACTION_SET_FILE_SIZE:
  995.                ReplyDosPacket(gd, gd->gd_Port,Pkt, -1,ERROR_ACTION_NOT_KNOWN);
  996.             break;
  997.  
  998.             case ACTION_DIE:
  999.                if (OpenCnt==0L)
  1000.                {
  1001.                   d(("opencnt = 0\n"))
  1002.  
  1003.                   if (IsListEmpty(&gd->gd_Port->mp_MsgList))
  1004.                   {
  1005.                      gd->gd_DosList->dol_Task = NULL;
  1006.  
  1007.                      ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
  1008.  
  1009.                      Done=TRUE;
  1010.                   }
  1011.                   else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  1012.                }
  1013.                else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
  1014.             break;
  1015.  
  1016.             default:
  1017.                ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
  1018.             break;
  1019.          }
  1020.       }
  1021.    }
  1022.    else ReplyDosPacket(gd, &gd->gd_We->pr_MsgPort, Pkt, DOSFALSE, ERROR_NO_FREE_STORE);
  1023.  
  1024.    closeres(gd);
  1025.  
  1026.    d(("returning\n"))
  1027.  
  1028.    return RETURN_OK;
  1029. }
  1030. /*E*/
  1031.  
  1032.